﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Controls.Primitives;
using Bling.DSL;
using Bling.DataBinding;
using Bling.Shapes;
using Bling.Geom;
using Bling.Animation;
using Bling.WPF;
using System.Windows.Shapes;

namespace Bling.Examples {
  class SingleShaderEffectCanvas : Canvas {

    public readonly Canvas Top = new Canvas();
    public readonly Canvas Middle = new Canvas();
    public readonly Canvas Bottom = new Canvas();

    public readonly Canvas Top0= new Canvas();
    public readonly Canvas Middle0 = new Canvas();

    private static readonly TypedDependencyProperty<SingleShaderEffectCanvas, Point> ElementCenterPositionProperty = "ElementCenterPosition".RegisterDp<SingleShaderEffectCanvas, Point>();
    private static readonly TypedDependencyProperty<SingleShaderEffectCanvas, double> ElementRadiusProperty = "ElementRadius".RegisterDp<SingleShaderEffectCanvas, double>();


    public readonly VisualBrush MyBrush = new VisualBrush() {
      Stretch = Stretch.None,
      TileMode = TileMode.None,
      ViewboxUnits = BrushMappingMode.RelativeToBoundingBox, Viewbox = new Rect(0, 0, 1, 1),
      ViewportUnits = BrushMappingMode.RelativeToBoundingBox, Viewport = new Rect(0, 0, 1, 1)

    };
    readonly Slider slider = new Slider();


    public SingleShaderEffectCanvas() {

      this.Background = new SolidColorBrush(Color.FromRgb(50, 50, 50));
      //this.Background = Brushes.White;

      MyBrush.Visual = Middle0;
      Middle.Background = null;
      
      Middle.Dsl().Size = this.Dsl().Size;
      Top.Dsl().Size = this.Dsl().Size;
      {
        slider.Dsl().Width = this.Dsl().Width;
        slider.Minimum = 0;
        slider.Maximum = 1;
        slider.Dsl().Bottom = this.Dsl().Height;
        slider.Dsl().Left = 0;
        slider.Dsl().ZIndex = 2;
        this.Children.Add(slider);
        slider.MouseEnter += (x, y) => {
          slider.Dsl().Value = slider.Dsl().Value;
          slider.Dsl().Value.Stop(false);

        };
      }

      var noiseBrush = new ImageBrush() {
        ImageSource = BlingExample.Properties.Resources.noise.LoadBitmap()
      };

      Func<BrushDSL, PointDSL, ColorDSL> noiseEffect = ( input, uv) => {
        BrushDSL fromBrush = MyBrush.Dsl();
        var sliderV = slider.Dsl().Value;
        var noiseBrush0 = noiseBrush.Dsl();

        var rgb = fromBrush[uv].ScRGB;
        rgb = fromBrush[uv].ScA.Lerp( input[uv].ScRGB, rgb);
        //var clr = new ColorDSL( rgb, fromBrush[uv].ScA.Max(input[uv].ScA));
        var clr = ColorDSL.FromScRgb( fromBrush[uv].ScA.Max(input[uv].ScA), rgb );

        //var uv2 = ((uv.X + (sliderV * 13)) % 1).MakePoint((uv.Y + (sliderV * 17)) % 1);
        var uv2 = new PointDSL((uv.X + (sliderV * 13)) % 1, (uv.Y + (sliderV * 17)) % 1 );
        var noise = noiseBrush0[uv2];
        var noiseX = (noise.ScR + noise.ScG + noise.ScB) / 3;

        var w0 = (1 - sliderV) * noiseX;
        var w1 = sliderV * (1 - noiseX);

        //return input[uv].Lerp(clr, w1 / (w0 + w1));
        return (w1/(w0+w1)).Lerp ( input[uv], clr );
      };

      Func<BrushDSL, PointDSL, ColorDSL> fadeInEffect = (input, uv) => {
        BrushDSL brush = MyBrush.Dsl();

        var rgb = brush[uv].ScA.Lerp(input[uv].ScRGB, brush[uv].ScRGB);

        //var clr = new ColorDSL(rgb, brush[uv].ScA.Max(input[uv].ScA));
        var clr = ColorDSL.FromScRgb(brush[uv].ScA.Max(input[uv].ScA), rgb);
        return slider.Dsl().Value.Lerp(input[uv], clr);
      };

      Func<MyScatterViewItem, BrushDSL, PointDSL, ColorDSL> myEffect = (item, input, uv) => {
        return input[uv];
      };

      Func<BrushDSL, PointDSL, ColorDSL> irisEffect = (input, uv) => {
        var s = 1 - slider.Dsl().Value;
        BrushDSL brush = MyBrush.Dsl();

        //var orig = new ColorDSL(brush[uv].ScA.Lerp(input[uv].RGB, brush[uv].RGB), brush[uv].ScA.Max(input[uv].ScA));
        var orig = ColorDSL.FromScRgb(brush[uv].ScA.Max(input[uv].ScA), brush[uv].ScA.Lerp(input[uv].ScRGB, brush[uv].ScRGB));

        //var orig = ColorSh.New(input[uv].RGB.Lerp(brush[uv].RGB, brush[uv].A), brush[uv].A.Max(input[uv].A));

        var d = (uv - ElementCenterPositionProperty.Dsl(this)).Length;
        var e = (s * ElementRadiusProperty.Dsl(this));
        var f = (d - e).Max(0);
        f = (f * 20).Min(1);
        var b = d < e;

        //return input[uv].Lerp(orig, f);
        return f.Lerp(input[uv], orig);
      };
      //Top0.Dsl().Effect = (input, uv) => myEffect(null, input, uv);

      Top0.Dsl().CustomEffect = irisEffect; // (input, uv) => input[uv];

      //Top0.Dsl().Effect = fadeInEffect;
      //var c = new CanvasDSL(this);
      //var b = new RectangleDSL(this);
      

      Top.Dsl().ZIndex = 2;
      Middle.Dsl().ZIndex = 1;
      Bottom.Dsl().ZIndex = 0;
      Top.Dsl().Size = this.Dsl().Size;
      Middle.Dsl().Size = this.Dsl().Size;
      Bottom.Dsl().Size = this.Dsl().Size;
      Middle.Dsl().Size = this.Dsl().Size;

      Top.Dsl().LeftTop = new Point(0, 0);
      Middle.Dsl().LeftTop = new Point(0, 0);
      Bottom.Dsl().LeftTop = new Point(0, 0);

      Children.Add(Bottom);
      {
        var rect = new Rectangle() { Stroke = Brushes.Black, StrokeThickness = 1 };
        rect.Dsl().LeftTop = new Point(0, 0);
        rect.Dsl().Size = Top.Dsl().Size;
        Middle0.Dsl().Size = Top.Dsl().Size;
        Middle0.Children.Add(Middle);
        Middle0.Children.Add(rect);
        Children.Add(Middle0);
      }
      {
        var rect = new Rectangle() { Stroke = Brushes.Black, StrokeThickness = 1 };
        rect.Dsl().LeftTop = new Point(0, 0);
        rect.Dsl().Size = Top.Dsl().Size;
        //Top0 = new CanvasDSL(this);
        Top0.Dsl().Size = Top.Dsl().Size;
        Top0.Children.Add(Top);
        Top0.Children.Add(rect);
        Children.Add(Top0);
      }


      var images = new Image[4];
      //images[0] = new ImageDSL(this) {Source = BlingExample.Properties.Resources.Autumn.LoadBitmap()};
      //images[0] = new Image() { Source = BlingExample.Properties.Resources.Autumn.LoadBitmap() };      
      images[0] = new Image() { Source = BlingExample.Properties.Resources.Autumn.LoadBitmap() };
      images[1] = new Image() { Source = BlingExample.Properties.Resources.Desert.LoadBitmap() };
      images[2] = new Image() { Source = BlingExample.Properties.Resources.Dock.LoadBitmap() };
      images[3] = new Image() { Source = BlingExample.Properties.Resources.Forest.LoadBitmap() };
      
      //PointDSL.IntersectionTest(this);
      this.Init(images);
      
    }

    public void BringToTop(FrameworkElement element, Point mousePos) {
      if (Top.Children.Contains(element)) return;
      while (Top.Children.Count > 0) {
        var child = Top.Children[0];
        Top.Children.RemoveAt(0);
        child.Effect = null;
        Middle.Children.Add(child);
      }
      var idx = Bottom.Children.IndexOf(element);
      if (idx != -1) {
        while (Bottom.Children.Count > idx + 1) {
          var child = Bottom.Children[Bottom.Children.Count - 1];
          Bottom.Children.RemoveAt(Bottom.Children.Count - 1);
          Middle.Children.Insert(0, child);
        }
        {
          var child = Bottom.Children[idx];
          Bottom.Children.RemoveAt(idx);
          Top.Children.Add(child);
        }
      } else {
        idx = Middle.Children.IndexOf(element);
        (idx != -1).Assert();
        for (int i = 0; i < idx; i++) {
          var child = Middle.Children[0];
          Middle.Children.RemoveAt(0);
          Bottom.Children.Add(child);
        }
        (Middle.Children[0] == element).Assert();
        Middle.Children.RemoveAt(0);
        Top.Children.Add(element);
      }
      var duration = 500;
      //element.Dsl().ScaleAt(element.Dsl().CenterSize).Animate
      element.Dsl().RenderTransform.ScaleXY.Animate.Duration(duration).Percents(0, 0.5, 1.0).Keys(1, 1.1, 1);
      

#if false
      element.ScaleXY(element.Center()).AnimateKey(new double[] { 1, 1.1, 1 }, new double[] { 0, 0.5, 1.0 },
        a => a.Duration(duration));

      if (true) {
        element.Effect = new DropShadowEffect() { Opacity = 0.5 };
        ((DropShadowEffect)element.Effect).Signal<double>(DropShadowEffect.ShadowDepthProperty).
          AnimateKey(new double[] { 0, 50, 0 }, new double[] { 0, 0.5, 1.0 }, a => a.Duration(duration));
      }
      // element.RenderTransform.Value
#endif

      //ElementCenterPositionProperty.Signal(this).Bind = element.CenterPosition() / Top.Size();


      ElementCenterPositionProperty.Dsl(this).Bind = mousePos / Top.Dsl().Size;
      var maxRadius = ((element.Dsl().LeftTop - mousePos) / Top.Dsl().Size).Length.Max(
                        ((element.Dsl().RightTop - mousePos) / Top.Dsl().Size).Length.Max(
                          ((element.Dsl().LeftBottom - mousePos) / Top.Dsl().Size).Length.Max(
                            ((element.Dsl().RightBottom - mousePos) / Top.Dsl().Size).Length)));

      ElementRadiusProperty.Dsl(this).Bind = maxRadius;

      
      slider.Dsl().Value.Stop(false);
      slider.Dsl().Value = 1d;
      //slider.Dsl().Value.Animate = AnimateTo(0, a => a.Duration(duration));
      slider.Dsl().Value.Animate.Duration(duration).To = 0;

      
      //slider.Dsl().Value.Value

      //slider.Value.Dsl().Animate = new Animate<double,DoubleDSL>() { T
    }

    private void Init ( Image[] images ) {
      var r = new Random();
      for (int i = 0; i < images.Length; i++) {
        var image = images[i];

        Middle.Children.Add(image);//should be middle

        var thumb = new ThumbDSL(this) { Width = 10, Height = 10, Background = Brushes.Red, ZIndex = 10, CanDrag = true };

        //thumb.DragDelta += (x, y) => ((Thumb)x).Dsl().LeftTop.Now += y.Delta();

        thumb.LeftTop = new Point(200 + 150 * r.NextDouble(), 200 + 150 * r.NextDouble());


        image.Dsl().CenterPosition = thumb;
        image.Dsl().Width = 250;

        image.Dsl().RenderTransform.Rotate = (r.NextDouble() * 360).Dsl().ToDegrees;

        image.MouseDown += (x, y) => {

          BringToTop((Image)x, y.GetPosition(this));

        };


        thumb.Visibility = image.Dsl().IsMouseOver | thumb.IsMouseOver;
      }
    }
  }


}